﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Security.Cryptography.PBKDF2;

namespace PBKDF2_Demo
{
    public partial class Form1 : Form
    {
        byte[] salt = null;

        public Form1()
        {
            InitializeComponent();

            saltButton_Click(this, EventArgs.Empty);
        }

        private void saltLengthSlider_ValueChanged(object sender, EventArgs e)
        {
            saltLabel.Text = string.Format("Salt Length: {0} Bytes", saltLengthSlider.Value);
        }

        private void saltInput_TextChanged(object sender, EventArgs e)
        {
            var hex = saltInput.Text;
            salt = Enumerable.Range(0, hex.Length)
                .Where(x => x % 2 == 0)
                .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                .ToArray();
        }

        private void saltButton_Click(object sender, EventArgs e)
        {
            salt = new byte[saltLengthSlider.Value];
            PBKDF2Helper.StaticRandomCryptoNumberGenerator.GetBytes(salt);

            saltInput.Text = salt.Aggregate(new StringBuilder(), (sb, x) => sb.AppendFormat("{0:X2}", x)).ToString();
        }

        private void iterationsSlider_ValueChanged(object sender, EventArgs e)
        {
            iterationsLabel.Text = string.Format("Iterations: {0}", iterationsSlider.Value);
        }

        private void keyLengthSlider_ValueChanged(object sender, EventArgs e)
        {
            keyLengthLabel.Text = string.Format("Key Length: {0} Bytes", keyLengthSlider.Value);
        }

        private void hashButton_Click(object sender, EventArgs e)
        {
            if (salt != null)
            {
                var start = DateTime.Now;
                var pbkdf2 = new Rfc2898DeriveBytes(passwordInput.Text, salt, iterationsSlider.Value);
                {
                    var key = pbkdf2.GetBytes(keyLengthSlider.Value);

                    hashOutput.Text = key.Aggregate(new StringBuilder(), (sb, x) => sb.AppendFormat("{0:X2}", x)).ToString();

                    System.Diagnostics.Debug.WriteLine(string.Format("Salt = {0}", saltInput.Text));
                    System.Diagnostics.Debug.WriteLine(string.Format("Password = {0}", passwordInput.Text));
                    System.Diagnostics.Debug.WriteLine(string.Format("Hash = {0}", hashOutput.Text));

                    System.Diagnostics.Debug.WriteLine(string.Format("Packed Hash = {0}",
                        PBKDF2Helper.GetPackedhash('-', iterationsSlider.Value, salt, key)));
                }
                var len = DateTime.Now.Subtract(start);
                System.Diagnostics.Debug.WriteLine(string.Format("Compute Time = {0}", len));
            }
        }

        private void randomHashButton_Click(object sender, EventArgs e)
        {
            int iterations = 0;
            byte[] salt = null, key = null;
            var packed = PBKDF2Helper.CreatePackedHash(passwordInput.Text, out iterations, out salt, out key);

            hashOutput.Text = key.Aggregate(new StringBuilder(), (sb, x) => sb.AppendFormat("{0:X2}", x)).ToString();

            iterationsSlider.Value = iterations;
            saltLengthSlider.Value = salt.Length;
            saltInput.Text = salt.Aggregate(new StringBuilder(), (sb, x) => sb.AppendFormat("{0:X2}", x)).ToString();
            keyLengthSlider.Value = key.Length;

            System.Diagnostics.Debug.WriteLine(string.Format("Packed Hash = {0}", packed));
        }
    }
}
